package multitester.annonations.processors;

import multitester.annonations.Exported;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Yuriy Sechko
 */
public class ExportedMethodsFinder
{
	private final Object instance;

	public ExportedMethodsFinder(final Object instance)
	{
		if (instance == null)
		{
			throw new IllegalArgumentException(
					"Input object should not be null.");
		}
		this.instance = instance;
	}

	private Map<String, VoidMethodPointer> findInClass(final Class clazz,
			final Map<String, VoidMethodPointer> alreadyFoundExported)
	{
		final Map<String, VoidMethodPointer> exportedMethods = new HashMap<String, VoidMethodPointer>();
		for (final Method currentMethod : clazz.getDeclaredMethods())
		{
			final Annotation demandedAnnotation = currentMethod
					.getAnnotation(Exported.class);
			if (demandedAnnotation == null)
				continue;
			final Exported actualAnnotation = (Exported) demandedAnnotation;
			final String alias = actualAnnotation.value();
			if (exportedMethods.get(alias) != null
					|| alreadyFoundExported.get(alias) != null)
				throw new IllegalStateException(
						"Some aliases of exported methods are duplicated.");
			exportedMethods.put(alias, new VoidMethodPointer(instance,
					currentMethod));
		}
		exportedMethods.putAll(alreadyFoundExported);
		if (clazz.getSuperclass() != null)
		{
			exportedMethods.putAll(findInClass(clazz.getSuperclass(),
					exportedMethods));
		}
		return exportedMethods;
	}

	public Map<String, VoidMethodPointer> find()
	{
		final Map<String, VoidMethodPointer> alreadyFoundExported = new HashMap<String, VoidMethodPointer>();
		return findInClass(instance.getClass(), alreadyFoundExported);
	}
}
